# src/llm_client.py
# -*- coding: utf-8 -*-
import os
import requests
from dataclasses import dataclass
from typing import List, Optional

@dataclass
class Role:
    name: str
    style: str

class LLMClient:
    """
    OpenAI 兼容接口（混元可用）。通过环境变量：
      LLM_API_BASE  e.g. https://api.hunyuan.cloud.tencent.com/v1
      LLM_API_KEY   e.g. sk-xxxx
      LLM_MODEL     e.g. hunyuan-large / hunyuan-turbo / ...
    """
    def __init__(self, mode: str = "openai_compatible"):
        self.mode = mode
        self.api_base = os.getenv("LLM_API_BASE", "https://api.hunyuan.cloud.tencent.com/v1")
        self.api_key  = os.getenv("LLM_API_KEY", "")
        self.model    = os.getenv("LLM_MODEL", "hunyuan-large")
        if not self.api_key:
            raise RuntimeError("缺少环境变量 LLM_API_KEY")

    # ---------- 外部入口 ----------
    def generate_dialogue(
        self,
        topic: str,
        roles: List[Role],
        minutes: int = 3,
        rounds: Optional[int] = None,
        mode: str = "normal",
        context: Optional[str] = None,
    ) -> str:
        """
        生成带 [角色] 标注的脚本。支持 mode=normal/deep。
        """
        if not rounds:
            rounds = max(4, int(minutes * 4.5))

        role_desc = "\n".join([f"- {r.name}：{r.style}" for r in roles])
        names = [r.name for r in roles]
        host = names[0]

        if mode == "deep":
            sys_prompt = f"""你是播客脚本编剧与逻辑写作专家，将围绕“{topic}”生成一段有深度、可引发思考的多角色脚本。
角色设定：
{role_desc}

已检索到的资料（可能只是一部分，请据此谨慎推断，必要时提示不确定性）：
{context or '（无）'}

写作要求：
- 结构：主持人抛题 → 嘉宾A观点+证据（含来源）→ 嘉宾B反方/补充+证据 → 主持人平衡、总结与行动建议。
- 每轮发言不超过2句，使用口语化承接（“我补充/我有不同看法/换个角度…”）。
- 在关键事实后用方括号注明简短来源（如：[出处：某报告 2024]）。
- 真实感与可执行性优先，避免空泛套话或自相矛盾。
输出严格使用如下格式（每行都以方括号角色名开头）：
[角色] 你的台词
"""
        else:
            sys_prompt = f"""你是播客脚本编剧。围绕主题“{topic}”生成自然互动的多角色对话脚本。
角色设定：
{role_desc}

要求：
- 共 {rounds} 轮；每轮两句以内；主持人负责抛题/追问/收束，嘉宾给观点/实例/注意事项。
- 使用自然口语化承接（“我也认同/不过我想补充/换个角度…”），避免重复与空洞表达。
- 输出严格使用如下格式（每行都以方括号角色名开头）：
[角色] 你的台词
"""

        user_prompt = f"请开始生成脚本。角色依次轮换，从“{host}”开场，共 {rounds} 轮。"

        return self._chat_completions(sys_prompt=sys_prompt, user_prompt=user_prompt)

    # ---------- OpenAI 兼容 ----------
    def _chat_completions(self, sys_prompt: str, user_prompt: str) -> str:
        url = f"{self.api_base.rstrip('/')}/chat/completions"
        headers = {"Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json"}
        body = {
            "model": self.model,
            "messages": [
                {"role": "system", "content": sys_prompt},
                {"role": "user",   "content": user_prompt},
            ],
            "temperature": 0.7,
        }
        resp = requests.post(url, headers=headers, json=body, timeout=120)
        resp.raise_for_status()
        data = resp.json()
        try:
            return data["choices"][0]["message"]["content"].strip()
        except Exception:
            return str(data)
